﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Runtime.Serialization;

namespace MediaRecommender.Model
{
    //Media types, each media is assigned a uniqued ID, this means we in equallity tests can use it to test.
    [Serializable()]
    abstract public class Media : IEquatable<Media>, ISerializable
    {
        protected static int idcounter;

        #region Fields
        private string _title;
        private int _id;
        private List<int> _genres;
        private string _coverUrl = "";
        protected List<bool> _vectorRepresentation; //Vector representing what features it has
        protected List<bool> _associatedPeopleVector; //Vector that represents what associated people are in the media
        protected double _vectorLength;
        #endregion

        #region Properties
        public string Title
        {
            get { return this._title; }
            protected set { this._title = value; }
        }

        public string CoverUrl 
        { 
            get { return _coverUrl; } 
            set { _coverUrl = value; } 
        }

        public int ID
        {
            get { return this._id; }
            protected set { this._id = value; }
        }

        public List<int> Genres
        {
            get { return this._genres; }
            protected set { this._genres = value; }
        }

        public List<bool> VectorRepresentation
        {
            get { return this._vectorRepresentation; }
            protected set { this._vectorRepresentation = value; }
        }

        public List<bool> AssociatedPeopleVector
        {
            get { return this._associatedPeopleVector; }
            protected set { this._associatedPeopleVector = value; }
        }

        public double VectorLength
        {
            get { return _vectorLength; }
            set { _vectorLength = value; }
        }
        #endregion

        #region Constructors
        protected Media()
        {
        }

        public Media(string title, List<int> genres, int id)
        {
            this.Title = title;
            this.Genres = genres;
            this.ID = id;
            this.VectorRepresentation = new List<bool>();
            this.AssociatedPeopleVector = new List<bool>();
            this.VectorLength = 0;
        }

        #endregion

        #region Serialization
        public virtual void GetObjectData(SerializationInfo info, StreamingContext ctxt)
        {
            info.AddValue("title", this.Title);
            info.AddValue("id", this.ID);
            info.AddValue("genres", this.Genres);
            info.AddValue("vectorRep", this.VectorRepresentation);
            info.AddValue("AssociatedPeopleVector", this.AssociatedPeopleVector);
            info.AddValue("VectorLength", this.VectorLength);
            info.AddValue("CoverUrl", this.CoverUrl);
        }
        #endregion

        #region Equals
        public override int GetHashCode()
        {
            return ID; //base.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            if (obj == null)
                return false;

            if (this.GetType() != obj.GetType())
                return false;

            return Equals((Media)obj);
        }

        public bool Equals(Media obj)
        {
            if (this.ID == obj.ID)
                return true;

            return false;
        }

        public static bool operator ==(Media leftMedia, Media rightMedia)
        {
            if (ReferenceEquals(leftMedia, null))
                return ReferenceEquals(rightMedia, null);

            return (leftMedia.Equals(rightMedia));
        }

        public static bool operator !=(Media leftMedia, Media rightMedia)
        {
            return !(leftMedia == rightMedia);
        }
        #endregion
    }

    [Serializable()]
    public class Book : Media
    {
        #region Book
        private List<Author> _authors;

        public List<Author> Author
        {
            get { return this._authors; }
            private set { this._authors = value; }
        }

        public Book(List<Author> authors, string title, List<int> genres, int id)
            : base(title, genres, id)
        {
            this.Author = authors;
        }

        #region Serialization
        public Book(SerializationInfo info, StreamingContext ctxt)
        {
            this.Title = (string)info.GetValue("title", typeof(string));
            this.ID = (int)info.GetValue("id", typeof(int));
            this.Genres = (List<int>)info.GetValue("genres", typeof(List<int>));
            this.VectorRepresentation = (List<bool>)info.GetValue("vectorRep", typeof(List<bool>));
            this.AssociatedPeopleVector = (List<bool>)info.GetValue("AssociatedPeopleVector", typeof(List<bool>));
            this.VectorLength = (double)info.GetValue("VectorLength", typeof(double));
            this.Author = (List<Author>)info.GetValue("author", typeof(List<Author>));

            }

        public override void GetObjectData(SerializationInfo info, StreamingContext ctxt)
        {
            info.AddValue("title", this.Title);
            info.AddValue("id", this.ID);
            info.AddValue("genres", this.Genres);
            info.AddValue("vectorRep", this.VectorRepresentation);
            info.AddValue("AssociatedPeopleVector", this.AssociatedPeopleVector);
            info.AddValue("VectorLength", this.VectorLength);
            info.AddValue("author", this.Author);
        }
        #endregion
        #endregion
    }

    [Serializable()]
    public class Movie : Media
    {
        #region Movie
        private Director _director;
        private List<Actor> _actor;

        public Director Director
        {
            get { return this._director; }
            private set { this._director = value; }
        }

        public List<Actor> Actors
        {
            get { return this._actor; }
            private set { this._actor = value; }
        }

        public Movie(Director director, List<Actor> actors, string title, List<int> genres, int id)
            : base(title, genres, id)
        {
            this.Director = director;
            this.Actors = actors;
        }

        #region Serialization
        public Movie(SerializationInfo info, StreamingContext ctxt)
        {
            this.Title = (string)info.GetValue("title", typeof(string));
            this.ID = (int)info.GetValue("id", typeof(int));
            this.Genres = (List<int>)info.GetValue("genres", typeof(List<int>));
            this.VectorRepresentation = (List<bool>)info.GetValue("vectorRep", typeof(List<bool>));
            this.AssociatedPeopleVector = (List<bool>)info.GetValue("AssociatedPeopleVector", typeof(List<bool>));
            this.VectorLength = (double)info.GetValue("VectorLength", typeof(double));
            this.Director = (Director)info.GetValue("Director", typeof(Director));
            this.Actors = (List<Actor>)info.GetValue("Actors", typeof(List<Actor>));
            this.CoverUrl = (string)info.GetValue("CoverUrl", typeof(string));

        }

        public override void GetObjectData(SerializationInfo info, StreamingContext ctxt)
        {
            info.AddValue("title", this.Title);
            info.AddValue("id", this.ID);
            info.AddValue("genres", this.Genres);
            info.AddValue("vectorRep", this.VectorRepresentation);
            info.AddValue("AssociatedPeopleVector", this.AssociatedPeopleVector);
            info.AddValue("VectorLength", this.VectorLength);
            info.AddValue("Director", this.Director);
            info.AddValue("Actors", this.Actors);
            info.AddValue("CoverUrl", this.CoverUrl);
        }
        #endregion
        #endregion
    }

    [Serializable()]
    public class VideoGame : Media
    {
        #region VideoGame
        private GameStudio _studio;
        private Publisher _publisher;
        private List<int> _platforms;

        public GameStudio Studio
        {
            get { return this._studio; }
            private set { this._studio = value; }
        }

        public Publisher Publisher
        {
            get { return this._publisher; }
            private set { this._publisher = value; }
        }

        public List<int> Platforms
        {
            get { return this._platforms; }
            private set { this._platforms = value; }
        }

        public VideoGame(GameStudio studio, Publisher publisher, List<int> platforms, string title, List<int> genres, int id)
            : base(title, genres, id)
        {
            this.Studio = studio;
            this.Publisher = publisher;
            this.Platforms = platforms;
        }

        #region Serialization
        public VideoGame(SerializationInfo info, StreamingContext ctxt)
        {
            this.Title = (string)info.GetValue("title", typeof(string));
            this.ID = (int)info.GetValue("id", typeof(int));
            this.Genres = (List<int>)info.GetValue("genres", typeof(List<int>));
            this.VectorRepresentation = (List<bool>)info.GetValue("vectorRep", typeof(List<bool>));
            this.AssociatedPeopleVector = (List<bool>)info.GetValue("AssociatedPeopleVector", typeof(List<bool>));
            this.VectorLength = (double)info.GetValue("VectorLength", typeof(double));
            this.Studio = (GameStudio)info.GetValue("Studio", typeof(GameStudio));
            this.Publisher = (Publisher)info.GetValue("Publisher", typeof(Publisher));
            this.Platforms = (List<int>)info.GetValue("Platforms", typeof(List<int>));

        }

        public override void GetObjectData(SerializationInfo info, StreamingContext ctxt)
        {
            info.AddValue("title", this.Title);
            info.AddValue("id", this.ID);
            info.AddValue("genres", this.Genres);
            info.AddValue("vectorRep", this.VectorRepresentation);
            info.AddValue("AssociatedPeopleVector", this.AssociatedPeopleVector);
            info.AddValue("VectorLength", this.VectorLength);
            info.AddValue("Studio", this.Studio);
            info.AddValue("Publisher", this.Publisher);
            info.AddValue("Platforms", this.Platforms);
        }
        #endregion
        #endregion
    }
}